package models;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import controllers.Game;

/**
 * 
 */

/**
 * @author Michal
 *
 */
public class Table {
	

	//sta�e
	public final byte GS_STOPPED = 0;
	public final byte GS_FIRST_BETTING = 1;
	public final byte GS_REPLACING = 2;
	public final byte GS_SECOND_BETTING = 3;
	public final byte GS_SUMUP = 4;
	
	public final byte MO_FOLD = 0;
	public final byte MO_BET = 1;
	public final byte MO_CHECK = 2;
	public final byte MO_RAISE = 3;
	public final byte MO_CALL = 4;
	public final byte MO_ALLIN = 5;
	public final byte MO_REPLACE = 6;
	public final byte MO_READY = 7;
	

	public final byte AB_NONE = 0;
	public final byte AB_CHECKBETFOLD = 1;
	public final byte AB_RAISECALLFOLD = 2;
	public final byte AB_FOLDALLIN = 3;
	public final byte AB_REPLACE = 4;
	public final byte AB_CONFIRM = 5;
	
	public final String[] handNames = {"high card", "one pair", "two pair", "three of a kind", "straight", "flush", "full house", "four of a kind", "straight flush"};
	
	//obiekty
	public Deck mainDeck;
	Player[] players;
	Random generator;
	Log log;
	Game GameController;
	
	//rozgrywka
	int turnBet;
	byte gameStatus = GS_STOPPED;	//status rozgrywki
	int startPlayer;
	int playerCounter;
	int ante;
	private int bets[];
	int previousBets[];
	private int lastBet[];
	byte lastMovement[];
	int cardsReplaced[];
	Boolean allInPlayed = false;
	Boolean betOpened;
	Boolean wrongMoveOccured = false;
	String sumUpString = "";
	String summaryString = "";
	
	int turnCount;
	
	//rozdanie
	int currentPlayer = 0;			//obecny gracz
	public int playerCount;
	//byte MoveStatus = 0;
	
	//wynik rozdania
	public int[] rank;
	public List<HandScore> scores;
	//private String message;
	
	/* KONSTRUKTORY */
	
	public Table(String name1, String name2, Boolean bot1, Boolean bot2, int startToken, int ante)
	{
		players = new Player[2];
		bets = new int[2];
		lastMovement = new byte[2];
		lastMovement[0] = MO_READY;
		lastMovement[1] = MO_READY;
		cardsReplaced = new int[2];
		setLastBet(new int[2]);
		if(bot1) players[0] = new AdvancedBot(this, name1, startToken,0);
		else players[0] = new Human(this, name1, startToken,0);
		
		if(bot2) players[1] = new AdvancedBot(this, name2, startToken,1);
		else players[1] = new Human(this, name2, startToken,1);
		
		log = new Log();
		
		playerCount = 2;
		
		this.ante = ante;
		
		turnCount = 0;
		
		generator = new Random();		
		startPlayer = generator.nextInt(2);
		
		try {
			mainDeck = new Deck();
		} catch (PokerException e) {
			// 
			e.printStackTrace();
		}
	}
	
	public Table(String name1, String name2, String name3, Boolean bot1, Boolean bot2, Boolean bot3, int startToken, int ante)
	{
		players = new Player[3];
		bets = new int[3];
		lastMovement = new byte[3];
		lastMovement[0] = MO_READY;
		lastMovement[1] = MO_READY;
		lastMovement[2] = MO_READY;

		cardsReplaced = new int[3];
		setLastBet(new int[3]);
		if(bot1) players[0] = new AdvancedBot(this, name1, startToken,0);
		else players[0] = new Human(this, name1, startToken,0);
		
		if(bot2) players[1] = new AdvancedBot(this, name2, startToken,1);
		else players[1] = new Human(this, name2, startToken,1);
		
		if(bot3) players[2] = new AdvancedBot(this, name3, startToken,2);
		else players[2] = new Human(this, name3, startToken,2);
		
		generator = new Random();		
		startPlayer = generator.nextInt(3);
		
		this.ante = ante;
		
		log = new Log();
		
		playerCount = 3;
		
		try {
			mainDeck = new Deck();
		} catch (PokerException e) {
			// 
			e.printStackTrace();
		}
		
		turnCount = 0;
	}
	
	public Table(String name1, String name2, String name3, String name4, Boolean bot1, Boolean bot2, Boolean bot3, Boolean bot4, int startToken, int ante)
	{
		players = new Player[4];
		bets = new int[4];
		lastMovement = new byte[4];
		lastMovement[0] = MO_READY;
		lastMovement[1] = MO_READY;
		lastMovement[2] = MO_READY;
		lastMovement[3] = MO_READY;
		cardsReplaced = new int[4];
		setLastBet(new int[4]);
		if(bot1) players[0] = new AdvancedBot(this, name1, startToken,0);
		else players[0] = new Human(this, name1, startToken,0);
		
		if(bot2) players[1] = new AdvancedBot(this, name2, startToken,1);
		else players[1] = new Human(this, name2, startToken,1);
		
		if(bot3) players[2] = new AdvancedBot(this, name3, startToken,2);
		else players[2] = new Human(this, name3, startToken,2);
		
		if(bot4) players[3] = new AdvancedBot(this, name4, startToken,3);
		else players[3] = new Human(this, name4, startToken,3);
		
		generator = new Random();		
		startPlayer = generator.nextInt(4);
		
		log = new Log();
		
		playerCount = 4;
		this.ante = ante;
		
		try {
			mainDeck = new Deck();
		} catch (PokerException e) {
			// 
			e.printStackTrace();
		}
		
		turnCount = 0;
	}
	
	List<Card> getPlayersCards(Player p)
	{
		return p.getCards();
	}
	
	public Player[] getPlayers()
	{
		return players;
	}
	
	public Player getPlayerByID( int ID ) 
	{
		//if (ID>players.length) return null;
			
		return players[ID];
	}
	
	public Player whoseTurn()
	{
		return players[currentPlayer];
	}
	
	public int getCurrentPlayer() 
	{
		return currentPlayer;
	}
	public void endTurn(int index)
	{
		log.print("OUT Tura gracza "+whoseTurn().getName());
		Player p = players[index];
		if(p == whoseTurn() )
		{
			System.out.print("NOTIFYENDTURN: ");
			System.out.print(lastMovement[currentPlayer]);
			System.out.println(gameStatus);
			if ( gameControllerExists() ) 
				GameController.NotifyEndTurn(currentPlayer, lastMovement[currentPlayer], gameStatus);
			
			byte state = nextPlayer();
			System.out.println("NEXT PLAYER");
			
			log.print("IN Tura gracza "+whoseTurn().getName());
			
			System.out.print("NOTIFYNEWTURN: ");
			System.out.print(checkAbility(currentPlayer));
			System.out.println(gameStatus);
			
			if ( gameControllerExists() && gameStatus != GS_STOPPED ) 
				GameController.NotifyNewTurn(currentPlayer, checkAbility(currentPlayer), gameStatus);
			
			if(state != GS_STOPPED)
			{
				players[currentPlayer].yourTurn(checkAbility(currentPlayer),turnBet-bets[currentPlayer]);
				if ( players[currentPlayer].isBot()) players[currentPlayer].endTurn();
			}
				
		}
	}
	
	public byte nextPlayer()
	{
		
		if(gameStatus == GS_STOPPED) return GS_STOPPED; //TODO: excezption
		
	/*	if(turnCount == 10)
		{
			stop();
			return GS_STOPPED;
		} */
		
		if(wrongMoveOccured)
		{
			wrongMoveOccured = false;
			return gameStatus;
		}
		
		if(gameStatus == GS_SUMUP)
		{
			if(playerCounter < getInGamePlayersCount())
			{
				currentPlayer = getNextInGamePlayerIndex();
				return GS_SUMUP;
			}
			else
			{	
				for(int i= 0; i< playerCount; i++)
				{
					if(players[i] == null || !players[i].enabled || players[i].left) continue;
					if(players[i].getTokens() < ante) 
					//wyrzucenie gracza
					{
						players[i].enabled = false;
					}
				}
				if(getEnabledPlayersCount() < 2)
				{
					endGame();
					return GS_STOPPED;
				}
				newDeal();
				startFirstBetting();
				return GS_FIRST_BETTING;
			}

			
		}
		
		if(getEnabledPlayersCount() < 2)
		{
			endGame();
			return GS_STOPPED;
		}
		
		if(getInGamePlayersCount() < 2) 
		{
			if(gameStatus == GS_FIRST_BETTING)
				previousBets = new int[playerCount];
			if(whoseTurn().left)
				currentPlayer = getNextInGamePlayerIndex();
			sumUp();
			return GS_SUMUP;
		}
		
			
		if(gameStatus == GS_FIRST_BETTING)
		{
			if(checkBettingEnd()) 
			{
				startReplacing();
				return GS_REPLACING;
			}
			else
			{
				currentPlayer = getNextInGamePlayerIndex();
				return GS_FIRST_BETTING;
			}
		}
		
		if(gameStatus == GS_REPLACING)
		{
			//jesli jeszcze nie wszyscy wymienili
			if(playerCounter < getInGamePlayersCount())
			{
				currentPlayer = getNextInGamePlayerIndex();
				return GS_REPLACING;
			}
			else
			{
				startSecondBetting();
				return GS_SECOND_BETTING;
			}
		}
		
		if(gameStatus == GS_SECOND_BETTING)
		{
			if(checkBettingEnd()) 
			{
				sumUp();
				return GS_SUMUP;
			}
			else
			{
				currentPlayer = getNextInGamePlayerIndex();
				return GS_SECOND_BETTING;
			}
		}		
		

		
		return GS_STOPPED;
		
	}
	
	public String getTurnResults()
	{
		int activeCount = getInGamePlayersCount();
		
		log.print("");		
		log.print(Integer.toString(turnCount)+" tura:");
		
		sumUpString = "";

		gameStatus = GS_SUMUP;
		
		//podliczanie zakladow

		int i;
		String message = "";
		
		message+="<p><strong>Turn "+Integer.toString(turnCount)+":</strong></p>";
		
		//bardzo patologiczna sytuacja
		if(activeCount == 0)
		{
			//TODO: obsluga mega patologicznej sytuacji
			return "<p>No players</p>";		
		}
		
		//tworzenie rankingu
		scores = new ArrayList<HandScore>(Evaluate.getScores(getInGamePlayers()));
		i = activeCount - 1;
		int j = activeCount - 2;
		rank = new int[activeCount];
		
		rank[i] = 1;
		int t = 1;
		
		while(j >= 0)
		{			
			if(scores.get(i).compareTo(scores.get(j)) > 0)
					t++;
		
			rank[j] = t;
			
			j --;
			i --;
		}
		

		
		Player winner = null;
		

		//patologiczna sytuacja
		if(activeCount == 1)
			winner = getInGamePlayers().get(0);
		//jesli jest wiecej graczy, ale nie bylo remisu
		else if(rank[activeCount-1] != rank[activeCount-2])
			winner = scores.get(activeCount-1).player;
			
		//jesli nie bylo remisu
		if(winner != null)
		{
			winner.win();
			if(!allInPlayed)
			{
				for(i=0;i<playerCount; i++)
					winner.addTokens(bets[i]);
			}
			else
			{
				int prize = bets[winner.index];
				for(i=0;i<playerCount; i++)
					if(bets[i]>=prize)
					{
						winner.addTokens(prize);
						if(winner.index != i) players[i].addTokens(bets[i]-prize);
					}
					else
					{
						winner.addTokens(bets[i]);
					}
			}
			message += "<p>Winner: <strong>"+winner.getName()+"</strong></p>";
		}
		//jesli byl remis
		else 
			message+= "<p><strong>Draw!</strong></p><p>";
		
		for(i = activeCount-1; i>=0; i--)
			message += "<br>"+Integer.toString(rank[i])+" - "+scores.get(i).player.getName()+" ("+handNames[scores.get(i).hand]+")";
		
		message+="</p>";
		
		return message;
	}
	
	
	public void sumUp()
	{
		String message = "";
		
		int i;
		for(i = 0; i<playerCount; i++)
		{
			bets[i] += previousBets[i];
		}
		
		message += getTurnResults();
		
		bets = new int[playerCount];
		
		//podliczanie zakladow
		
		message += getTokenRankMessage();
		
		log.print(message);

		playerCounter = 0;
		
		gameStatus = GS_SUMUP;

		sumUpString = message;
		
		for(i= 0; i<playerCount; i++)
			players[i].folded = false;
		
		startPlayer = getEnabledPlayerAfterThis(startPlayer);
		
	}
	
	public int[] getPlayersCardsID(int PlayerID)
	{
		List<Card> cards = players[PlayerID].getCards();
		int [] cardIds = new int[5];
		int i = 0;
		Iterator<Card> itr = cards.iterator();
	    while(itr.hasNext()) {
	    	Card element = itr.next();
	    	cardIds[i] = element.getCardID();
	    	i++;
	    }
	    int j;
	    for(j = i; j<5; j++)
	    	cardIds[j] = 1;
	    	
	    return cardIds;
	}
	
	public void playerLeave(int index)
	{
		System.out.println("INPLAYERLEAVE");
		System.out.println(gameStatus);
		
		if(gameStatus == GS_STOPPED) return;
		
		if(getInGamePlayersCount() <= 1)
		{
			endGame();
			return;
		}
		
		if(index == currentPlayer)
		{
			if(gameStatus == GS_FIRST_BETTING)
				move(index,MO_FOLD,0);
			else if(gameStatus == GS_REPLACING)
			{
				int[] cards = new int[5];
				move(index,cards);
				playerCounter --;
			}
			else if(gameStatus == GS_SECOND_BETTING)
				move(index,MO_FOLD,0);
			else if(gameStatus == GS_SUMUP)
			{
				move(index);
				playerCounter --;
			}
			players[index].enabled = false;
			players[index].fold();
			players[index].leave();
			endTurn(index);
			return;
		}	
		
		players[index].enabled = false;
		players[index].fold();
		players[index].leave();
		

	}
	
	public int getNextInGamePlayerIndex()
	{
		int i = currentPlayer+1;
		while(true)
		{
			if(i==playerCount) i =0;
			if(players[i] != null)
				if(players[i].enabled && !players[i].folded && !players[i].left)
					break;
			i++;				
		}
		return i;
	}
	
	public void startFirstBetting()
	{
		gameStatus = GS_FIRST_BETTING;
		bets = new int[playerCount];
		previousBets = new int[playerCount];
		cardsReplaced = new int[playerCount];
		setLastBet(new int[playerCount]);
		turnBet = 0;
		playerCounter = 0;
		allInPlayed = false;
		betOpened = false;
		
		currentPlayer = startPlayer;
		currentPlayer = getNextInGamePlayerIndex();
		
		//wpisowe
		
		int i;
		for(i= 0; i< playerCount; i++)
		{
			if(players[i] == null || !players[i].enabled || players[i].left) continue;
			if(players[i].getTokens() < ante) 
			//wyrzucenie gracza
			{
				players[i].enabled = false;
			}
			else
			{
				players[i].betTokens(ante);
				bets[i] = ante;
				turnBet += ante;
			}
		}
		
		turnCount ++;

	}
	
	public void startReplacing()
	{
		gameStatus = GS_REPLACING;
		
		previousBets = bets;
		
		bets = new int[playerCount];
		
		currentPlayer = getNextInGamePlayerIndex();	
		
		cardsReplaced = new int[playerCount];
		
	}
	
	public void startSecondBetting()
	{
		gameStatus = GS_SECOND_BETTING;
		
		//rozdanie kart
		mainDeck.shuffleCurrent();
		
		for(int i = 0; i<playerCount; i++)
		{
			for(int j=0; j<cardsReplaced[i]; j++)
				try { players[i].addCard(mainDeck.pop()); }
				catch(PokerException e) {}
		}
		
		turnBet = 0;
		playerCounter = 0;
		betOpened = false;

		
		if(allInPlayed)
		{
			sumUp();
			return;
		}		
		
		currentPlayer = startPlayer;
		currentPlayer = getNextInGamePlayerIndex();
		
	}
	
	public int getEnabledPlayersCount()
	{
		int i;
		int j = 0;
		for(i = 0; i< playerCount; i++)
		{
			if(players[i] != null && players[i].enabled && !players[i].left)
				j++;
		}
		return j;
	}
	
	public int getInGamePlayersCount()
	{
		int i;
		int j = 0;
		for(i = 0; i< playerCount; i++)
		{
			if(players[i] != null && players[i].enabled && !players[i].folded && !players[i].left)
				j++;
		}
		return j;
	}
	
	public String getSumUpString()
	{
		return sumUpString;
	}
	
	public int getEnabledPlayerAfterThis(int index)
	{
		int i = index+1;
		while(true)
		{
			if(i==playerCount) i = 0;
			if(players[i] != null)
				if(players[i].enabled && !players[i].left)
					break;
			i++;				
		}
		return i;
	}
	
	
	public List<Player> getInGamePlayers()
	{
		List<Player> resultList = new ArrayList<Player>();
		int i;
		for(i = 0; i<playerCount; i++)
		{
			if(players[i] != null && players[i].enabled && !players[i].folded && !players[i].left)
				resultList.add(players[i]);
		}
		return resultList;
	}
	
	public void start()
	{

		newDeal();

		startFirstBetting();	
		
		if ( gameControllerExists() )  {
			GameController.NotifyStartGame(gameStatus);
			GameController.NotifyNewTurn(currentPlayer, checkAbility(currentPlayer), gameStatus);
		}
			
		players[currentPlayer].yourTurn(checkAbility(currentPlayer),0);
		if ( players[currentPlayer].isBot()) players[currentPlayer].endTurn();
	}
	
	public void stop()
	{
		gameStatus = GS_STOPPED ;
	}
	
	public void endGame()
	{
		stop();
		
		summaryString = "<p>GAME FINISHED</p>";
	
		summaryString += getTokenRankMessage();
		
		if ( gameControllerExists() ) 
			GameController.NotifyEndGame(gameStatus,summaryString);
		
	}
	
	public String getSummaryString() {
		
		return summaryString;
	}
	
	private String getTokenRankMessage() {
		
		// �ETONY
		String mes = "<p>";
		List<Player> playerRank = new ArrayList<Player>();
		int rank[];
		int i;
		for(i = 0; i<playerCount; i++)
		{
			if(players[i] != null)
				if(!players[i].left)
					playerRank.add(players[i]);
		}
		
		Collections.sort(playerRank);
		
		int l = playerRank.size();
		
		System.out.println(l);
		
		rank = new int[l];
		if(l>0)
			rank[l-1] = 1;
		
		mes = "1: "+playerRank.get(l-1).getName()+" ("+Integer.toString(playerRank.get(l-1).getTokens())+" tokens, "+Integer.toString(playerRank.get(l-1).getVictories())+" wins)<br>";
		
		if(l>1)
			for(i = l-2; i>=0; i--)
			{
				if(playerRank.get(i) == playerRank.get(i+1))
					rank[i] = rank[i+1];
				else
					rank[i] = rank[i+1]+1;
				
				mes += Integer.toString(rank[i])+": "+playerRank.get(i).getName()+" ("+Integer.toString(playerRank.get(i).getTokens())+" tokens, "+Integer.toString(playerRank.get(i).getVictories())+" wins)<br>";
			}
		
		
		return mes+"</p>";
		
	}

	//rozdanie
	public void newDeal()
	{
		int i;
		try {
			mainDeck.shuffleNew();
		} catch (PokerException e) {
			// 
			e.printStackTrace();
		}
		currentPlayer = 0;
		
		for(i=0;i<playerCount;i++)
		{
			players[i].reset();
			if(!players[i].enabled || players[i].left) continue;
			try {
				players[i].addCards(mainDeck.pop(), mainDeck.pop(), mainDeck.pop(), mainDeck.pop(), mainDeck.pop());
			} catch (PokerException e) {
				// 
				e.printStackTrace();
			}
		}
		
	}
	
	public byte checkAbility(int index)
	{
		Player player = players[index];
		
		//brak mozliwosci zagrania
		if(player == null || !player.enabled || (gameStatus == GS_STOPPED) || currentPlayer != index || player.left )
			return AB_NONE;
		
		//mozliwosc potwierdzenia dalszej gry
		if(gameStatus == GS_SUMUP)
			return AB_CONFIRM;
		
		if(player.folded)
			return AB_NONE;
		
		//mozliwosc wymiany
		if(gameStatus == GS_REPLACING)
			return AB_REPLACE;
		
		//mozliwosc all-in i fold (bo ktos juz zagral)
		if(allInPlayed)
			return AB_FOLDALLIN;
			
		//mozliwosc check i bet, fold
		if(!betOpened)
			if(player.getTokens()>1)
				return AB_CHECKBETFOLD;
			else
				return AB_FOLDALLIN;
		
		//mozliwosc all-in i fold (za malo zetonow na call lub raise)
		if(player.getTokens() <= (turnBet+1)-bets[player.index])
		{
			System.out.print(player.getName()+ " ");
			System.out.println(turnBet+1);
			System.out.println(bets[player.index]);
			System.out.println((turnBet+1)-bets[player.index]);
			return AB_FOLDALLIN;
		}
		
		//mozliwosc call, raise, fold
		return AB_RAISECALLFOLD;
	}
	
	public Boolean checkBettingEnd()
	{
		int i = 0;
		int bet = 0;
	//	log.print("Sprawdzam czy koniec licytacji");
		Boolean first = true;
		Boolean end = true;
		if(!allInPlayed)
		{
			if(!betOpened) return false;
			while(i<playerCount)
			{
				if(players[i].enabled && !players[i].folded && !players[i].left)
					if(first) {
						bet = bets[i];
						first = false;
					} else if(bets[i] != bet) 
					{
						end = false;
						break;
					}
				i++;
			}
			return end;
		}
		else
		// by�o allIn
		{
			System.out.println("ALL IN KURWO");
			while(i<playerCount)
			{
				if(players[i].enabled && !players[i].left)
				{
					if(lastMovement[i] != MO_FOLD && lastMovement[i] != MO_ALLIN)
					{
						end = false;
						break;
					}
				}
				i++;
			}
			return end;
		}
	}
	
	public void move(int index, int cards[])
	{
		//players[index].showCards();
		//sprwadza czy wymiana
		if(checkAbility(index)!=AB_REPLACE)
		{
			wrongMove(index,MO_REPLACE,"You can't replace now");
			return;
		}
		List<Card> tempCards = new ArrayList<Card>();
		int i;
		
		//sprawdza czy tablica jest odpowiednia
		if (cards.length!=5)
		{
			wrongMove(index,MO_REPLACE,"Wrong count of cards to replace");
			return;
		}
		
		//dodaje karty od gracza
		for (i = 0; i<5; i++)
		{
			if(cards[i]==0) continue;
			for(int j = 0; j<5; j++)
			{
				if(players[index].getCards().get(j).compareTo(Integer.valueOf(cards[i])) == 0)
				{
					tempCards.add(players[index].getCards().get(j));
				}
			}			
		}
		
		//usuwa karty graczowi i dodaje je do talii
		int l = tempCards.size();
		for (i = 0; i<l; i++)
		{
			try {
				players[index].discardCard(tempCards.get(i));
			} catch (PokerException e)
			{
				wrongMove(index,MO_REPLACE, e.getMessage());
				return;
			}
			mainDeck.push(tempCards.get(i));
		}		
		
		playerCounter++;
		cardsReplaced[index] = l;
		lastMovement[index] = MO_REPLACE;
		log.print(players[index].getName()+" wymienia "+Integer.toString(l));
	
	//	players[index].showCards();
	}
	
	public void move(int index)
	{
		byte ability = checkAbility(index);
		
		if(ability != AB_CONFIRM)
		{
			wrongMove(index,MO_READY,"You can't confirm now");
			return;
		}
		
		
		lastMovement[index] = MO_READY;
		playerCounter ++;
		log.print(players[index].getName()+" potwierdza dalsza gre");
	}
	
	public void move(int index, byte movement, int bet)
	{
		byte ability = checkAbility(index);
		
	//	log.print(Integer.toString((int)ability));
		
		//jesli to nie licytacja
		if(ability == AB_REPLACE)
		{
			wrongMove(index,movement,"It's not time for betting");
			return;
		}
		if(ability == AB_NONE)
		{
			wrongMove(index,movement,"You can't make a move now");
			return;		
		}
		//fold mozna zawsze
		if(movement == MO_FOLD)
		{
			lastMovement[index] = movement;
			players[index].fold();
			log.print(players[index].getName()+" folds  ("+Integer.toString(bets[index])+")");
			return;
		}
			
		if(ability == AB_CHECKBETFOLD)
		{
				
			if(movement == MO_BET)
			{
				if(bet<=0) 
				{
					wrongMove(index, movement, "You have to bet something (bet)");
					return;					
				}
				if(players[index].getTokens() <= bet)
				{
					wrongMove(index,movement,"You bet more than you have (bet) (you have "+Integer.toString(players[index].getTokens())+", you bet "+Integer.toString(bet)+")");
					return;
				}
				players[index].betTokens(bet);
				bets[index] += bet;			
				lastMovement[index] = movement;
				lastBet[index] = bet;
				turnBet = bets[index];
				betOpened = true;
				log.print(players[index].getName()+" bets "+Integer.toString(bet)+"  ("+Integer.toString(bets[index])+")");
				return;
			}
			if(movement == MO_CHECK)
			{
				lastMovement[index] = movement;
				lastBet[index] = 0;
				log.print(players[index].getName()+" checks ("+Integer.toString(bets[index])+")");
				return;
			}
			wrongMove(index,movement,"Licytacja nieotwarta");
			return;
		}
		
		if(ability == AB_FOLDALLIN)
		{
			if(movement == MO_ALLIN)
			{
				if(!allInPlayed) 
					allInPlayed = true;
				lastBet[index] = players[index].getTokens();
				bets[index] += players[index].getTokens();
				players[index].betTokens(players[index].getTokens());
				lastMovement[index] = movement;
				log.print(players[index].getName()+" all in ("+Integer.toString(bets[index])+")");
				return;
			}
			wrongMove(index, movement, "You can either go all in or fold");
			return;
			
		}

		if(ability == AB_RAISECALLFOLD)
		{
		
			if(movement == MO_RAISE)
			{
				if(players[index].getTokens() <= bet)
				{
					wrongMove(index,movement,"You bet more than you have (raise). You have "+Integer.toString(bet)+" ("+Integer.toString(bets[index]+bet)+") but you've got "+Integer.toString(players[index].getTokens())+" and you need to bet "+Integer.toString(turnBet+1));
					return;
				}
				if(bets[index]+bet <= turnBet)
				{
					wrongMove(index,movement,"You bet too little (raise). You bet "+Integer.toString(bet)+" (total "+Integer.toString(bets[index]+bet)+") and you need over "+Integer.toString(turnBet));
					return;
				}
				bets[index] += bet;
				turnBet = bets[index];
				lastBet[index] = bet;
				players[index].betTokens(bet);
				lastMovement[index] = movement;
				log.print(players[index].getName()+" raises to "+Integer.toString(bets[index])+" ("+Integer.toString(bets[index])+")");
				return;
			}
			if(movement == MO_CALL)
			{
				if(players[index].getTokens() <= turnBet-bets[index])
				{
					wrongMove(index,movement,"You bet more than you have (call). You have "+Integer.toString(players[index].getTokens())+" but you need "+Integer.toString(turnBet));
					return;
				}
				bet = turnBet - bets[index];
				lastBet[index] = bet;
				bets[index] = turnBet;
				players[index].betTokens(bet);
				lastMovement[index] = movement;
				log.print(players[index].getName()+" calls ("+Integer.toString(bets[index])+")");
				return;
			}
		}
		
		//z�e
		wrongMove(index,movement,"Wrong move");
		
	}
	
	public void wrongMove(int index, byte movement, String mes)
	{
		log.print(players[index].getName()+": "+mes);
		wrongMoveOccured = true;
		
		if ( gameControllerExists() ) GameController.NotifyWrongMove(index, mes);
	}

	public int[] getLastBet() {
		return lastBet;
	}

	public void setLastBet(int lastBet[]) {
		this.lastBet = lastBet;
	}

	public int[] getBets() {
		int i;
		int[] tab = new int[playerCount];
		for(i = 0; i<playerCount; i++)
			tab[i] = bets[i]+previousBets[i];
		return tab;
	}

	private boolean gameControllerExists() {
		if ( GameController != null ) return true;
		
		return false;
	}
	
	public void setGameController( Game Controller ) {
		this.GameController = Controller;
	}

	public byte[] getLastMovement() {
		
		return lastMovement;
	}

}
